[CPU編]AWS ParallelCluster SlurmにCPU系ジョブを投げるとクラスターがどうスケールするか試してみた
AWS ParallelClusterのジョブスケジューラーに伝統的なスケジューラーを利用すると、コンピュートフリートはAmazon EC2 Auto Scaling Group(ASG)で管理され、ASGの機能を用いてスケールします。
ジョブスケジューラーのSlurmにCPUベースのジョブを投げ、ジョブがどのようにノードに割り振られ、フリートがスケールするのか、主に ユーザー↔ジョブスケジューラー(Slurm)間のジョブ操作の観点から試してみました。
GPU 編はこちら
環境
- AWS ParallelCluster : 2.7
- ジョブスケジューラー : Slurm Workload Manager (Slurm)
- Intel ハイパースレッディング : 無効
- コンピュートノードのvCPU : デフォルトでは8vCPU。HTを無効化にして4vCPUで動作
- ノードの台数 : 最大8(max_queue_size=8)
やり方
AWS ParallelCluster で ハイパースレッディング(HT)を無効化したコンピュートノード構成します。
利用可能なノード数・vCPU数によってジョブスケジューラーがどのようにジョブを割り振り、フリートをスケールさせるのか確認します。
実行に5分かかるスクリプトを用意します。
#!/bin/sh srun -l /bin/hostname sleep 300
このスクリプトを元に、以下の様なジョブを投げます。
- job1 : 2 ノード、合計4タスク(2タスク/ノード)
$ sbatch -N2 -n4 --job-name job1 my.script
- job2 : 3 ノード、合計3タスク(1タスク/ノード)
$ sbatch -N3 -n3 --job-name job2 my.script
- job3 : 1 ノード、合計2タスク(2タスク/ノード)
$ sbatch -N1 -n2 --job-name job3 my.script
ジョブ投入時のコンピュートフリートのアイドルなノード数によって、ジョブがどのように振り分けられ、ノードがどのように増えるのか確認します。
各ノードのvCPU数はHTを無効にした状態で4です。
シナリオ1 : フリートが 0 台の時にジョブを投げる
コンピュートノードが0台のフリートを用意します。
$ sinfo PARTITION AVAIL TIMELIMIT NODES STATE NODELIST compute* up infinite 0 n/a
この状態でジョブを投げます。
$ sbatch -N2 -n4 --job-name job1 my.script Submitted batch job 2 $ sbatch -N3 -n3 --job-name job2 my.script Submitted batch job 3 $ sbatch -N1 -n2 --job-name job3 my.script Submitted batch job 4
3ジョブがキューイングされます。
$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 2 compute job1 centos PD 0:00 2 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) 3 compute job2 centos PD 0:00 3 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) 4 compute job3 centos PD 0:00 1 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) $ squeue --long Thu Aug 13 02:00:53 2020 JOBID PARTITION NAME USER STATE TIME TIME_LIMI NODES NODELIST(REASON) 2 compute job1 centos PENDING 0:00 UNLIMITED 2 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) 3 compute job2 centos PENDING 0:00 UNLIMITED 3 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) 4 compute job3 centos PENDING 0:00 UNLIMITED 1 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions)
/var/log/jobwatcher
を確認すると、ジョブに必要なスロットをもとに、新規に 3ノード起動しようとしています。
内部的には、Auto Scaling Groupのdesired capacity を 3 にしています。
2020-08-13 02:00:05,293 INFO [utils:get_optimal_nodes] Processing job that requested 2 nodes and the following resources: {'gpus': 0, 'slots': 4} 2020-08-13 02:00:05,293 INFO [utils:get_optimal_nodes] Processing job that requested 3 nodes and the following resources: {'gpus': 0, 'slots': 3} 2020-08-13 02:00:05,293 INFO [utils:get_optimal_nodes] Processing job that requested 1 nodes and the following resources: {'gpus': 0, 'slots': 2} 2020-08-13 02:00:05,293 INFO [utils:get_optimal_nodes] Computed following allocation for required nodes [{'slots': 1, 'gpus': 0}, {'slots': 1, 'gpus': 0}, {'slots': 1, 'gpus': 0}] 2020-08-13 02:00:05,293 INFO [jobwatcher:_poll_scheduler_status] 3 nodes requested, 0 nodes busy or unavailable 2020-08-13 02:00:05,293 INFO [jobwatcher:_poll_scheduler_status] Setting desired to 3 nodes, requesting 3 more nodes from asg. 2020-08-13 02:01:05,333 INFO [utils:get_asg_settings] ASG min/desired/max: 0/3/8
ノードが3台立ち上がると、ジョブが3ノードに割り振られています。
$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 2 compute job1 centos R 1:01 2 ip-10-1-21-[30,95] 3 compute job2 centos R 1:01 3 ip-10-1-21-[30,95,179] 4 compute job3 centos R 1:01 1 ip-10-1-21-179 # 簡易表示 $ sinfo PARTITION AVAIL TIMELIMIT NODES STATE NODELIST compute* up infinite 3 mix ip-10-1-21-[30,95,179] # ノード別表示 $ sinfo --Node --long Thu Aug 13 02:06:13 2020 NODELIST NODES PARTITION STATE CPUS S:C:T MEMORY TMP_DISK WEIGHT AVAIL_FE REASON ip-10-1-21-30 1 compute* mixed 4 4:1:1 1 0 1 (null) none ip-10-1-21-95 1 compute* mixed 4 4:1:1 1 0 1 (null) none ip-10-1-21-179 1 compute* mixed 4 4:1:1 1 0 1 (null) none
sinfo
の出力で STATE
が mix/mixed
となっているのは、4vCPU に対して、まだ空きスロット(idle枠)があるためです。
すべて埋まると alloc/allocated
になります。
3ノードあれば、3ジョブを並列で全て処理できるため、最小の3ノードだけ起動したものと思われます。
シナリオ2 : フリートが 2 台の時にジョブ投下
同様の手順で、フリートが 2台のときにジョブを投げてみます。
結果、まずはアクティブな2台で、2ノードで処理可能なジョブを処理しました。
$ sinfo --Node --long Thu Aug 13 01:48:14 2020 NODELIST NODES PARTITION STATE CPUS S:C:T MEMORY TMP_DISK WEIGHT AVAIL_FE REASON ip-10-1-21-164 1 compute* allocated 4 4:1:1 1 0 1 (null) none ip-10-1-21-238 1 compute* mixed 4 4:1:1 1 0 1 (null) none $ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 7 compute job2 centos PD 0:00 3 (Nodes required for job are DOWN, DRAINED or reserved for jobs in higher priority partitions) 6 compute job1 centos R 0:23 2 ip-10-1-21-[164,238] 8 compute job3 centos R 0:23 1 ip-10-1-21-164
3ノード以上確保できたタイミングで、ジョブ実行に3ノード必要な job2 が処理されました。
$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 7 compute job2 centos R 0:08 3 ip-10-1-21-[99,124,164] $ sinfo --Node --long Thu Aug 13 01:53:32 2020 NODELIST NODES PARTITION STATE CPUS S:C:T MEMORY TMP_DISK WEIGHT AVAIL_FE REASON ip-10-1-21-99 1 compute* mixed 4 4:1:1 1 0 1 (null) none ip-10-1-21-124 1 compute* mixed 4 4:1:1 1 0 1 (null) none ip-10-1-21-164 1 compute* mixed 4 4:1:1 1 0 1 (null) none ip-10-1-21-238 1 compute* idle 4 4:1:1 1 0 1 (null) none ip-10-1-21-253 1 compute* idle 4 4:1:1 1 0 1 (null) none
起動ずみ2ノードで処理可能なジョブは処理しつつ、job2 向けに3ノード追加し、合計5台になりました。
CPU の空きスロットを考慮すると、2ノード追加すれば job2 も処理できますが、そのようにはなりませんでした。
ドキュメントに記載されているように、ジョブを実行しているノードはビジーノードとみなされ、job2 向けに別途3ノード追加されたものと思われます。
現在の制限: 自動スケールアップロジックは、部分的にロードされたビジーノードを考慮しません。つまり、ジョブを実行しているノードは、空のスロットがある場合でも、ビジー状態と見なされます。
https://docs.aws.amazon.com/ja_jp/parallelcluster/latest/ug/autoscaling.html
※ 5ノード目の「ip-10-1-21-253」を起動しなくても、job2 は実行できる
さらに
- ip-10-1-21-99
- ip-10-1-21-124
- ip-10-1-21-253
の3台は3ノード必要な job2 のために新規に起動しましたが、job2 の実際の処理は
- ip-10-1-21-99
- ip-10-1-21-124
- ip-10-1-21-164
の3台で行われました。
ノードの追加命令と、ジョブスケジューラーがジョブをどのように割り振るかは独立していることがわかります。
※ ノード追加のトリガーとなったジョブが、実際に追加されたジョブで処理されたとしたら、このようになる。
シナリオ3:フリートが4台のときにジョブ投下
4台 idle のフリートを用意します。
$ sinfo PARTITION AVAIL TIMELIMIT NODES STATE NODELIST compute* up infinite 4 idle ip-10-1-21-[43,164,212,238]
ジョブを投入すると、シナリオ1のときと同じく、3ノードだけですべてのジョブを処理しました。
$ squeue JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 3 compute job1 centos R 1:22 2 ip-10-1-21-[43,164] 4 compute job2 centos R 1:22 3 ip-10-1-21-[43,164,212] 5 compute job3 centos R 1:18 1 ip-10-1-21-212
空きスロットのあるノードだけで処理できる場合は、全スロットが空いているノードには手を付けないようです。
ジョブスケジューラー(Slurm)↔Auto Scaling Group間のノードのスケーリングについて
Slurm(ジョブスケジューラー)↔Auto Scaling Group間のノードのスケーリングについては、次のドキュメントで詳細に記載されています。
How AWS ParallelCluster works - AWS ParallelCluster
- ジョブスケジューラーにノード追加が必要化チェックする jobwatcher
- ASG によりノードの追加・削除されたイベントをジョブスケジューラーに通知する sqswatcher
- コンピュートノードで idle 状態が続き、ノードの削除が必要化チェックする nodewatcher
などが裏方として活躍しています。
最後に
ParallelCluster がどのようにノードを増減し、ジョブスケジューラーがどのようにジョブをノードに割り振るのか、ある程度把握しておくと
- ノードを常に何台稼働させておくか
- ノードを最大で何台まで稼働させるか
といったシミュレーションをしやすくなると思います。
Slurm の CPU リソース管理の詳細については、次のドキュメントを参照ください。
Slurm Workload Manager - CPU Management User and Administrator Guide
それでは。